/*
*
 * @author Jospeh Conrad Stack
 *
 * a unix style shell which continues to prompt for commands until
 * the user decides to 'logout'.  
 * @param prompt a string containing the prompt
 * @param IN is the int holding the input file redirection
 * @param OUT is the int holding the output file redirection
 * @param ERR is the int holding the error file redirection
 * @param args[] is an array holding a list of command line arguments
 */ 

#include <stdio.h>
#include <fcntl.h>
#include <stdlib.h>
#include <string.h>


/*
* see README file immediately, if you haven't already
 */ 


int forkmebaby(char* args[]);

/* global variables */
char prompt[30];     
int IN,OUT,ERR,fd[2];
char* args[8];


/* main method, contains all processing, aside from pipes */
int main(){
    
    
    char* op;
    char* command;
    int i=1;
    int id,status,argnum;
    int outREDIR,inREDIR,errREDIR;
    char line[200];

    strcpy(prompt,"OH YEAH%");
    
    
    /* start looping for the shell */
    while(1){
        
        printf("%s ",prompt);
        fgets(line,sizeof(line),stdin);
        
        /* check to see if user just hit enter key */
        if(strcmp(line,"\n")==0 | strcmp(line,"\t\n")==0 | strcmp(line," \n")==0)
            continue;
       
       /* get the first command */
       command = strtok(line," \t\n");
       args[0] = malloc(sizeof(command));
       strcpy(args[0],command);
            

       /* check to see if the user wants to change to prompt */
       if(strcmp(args[0],"prompt")==0){
            if((op = strtok(NULL," \t\n")) != NULL){
                strcpy(prompt,op);
            }
        }
        
       /* check to see if the user wants to logout */
        else if(strcmp(args[0],"logout")==0)
            return EXIT_SUCCESS;


       /* user has entered a non-generic command, get arguments and check for redirection/piping */
        else{
            id = fork();
            if(id == 0){
                args[0] = malloc(sizeof(command));
                strcpy(args[0],command);
                outREDIR = 0;
                inREDIR = 0;
                errREDIR = 0;
                i=1;
                status = 0;
                

                while(1){
                    
                    /* get next argument */
                    if((op = strtok(NULL," \t\n")) != 0){
                        
                        /* redirect standard in */
                        if(inREDIR == 1){
                            if((IN = open(op,O_RDONLY)) == NULL){
                                    perror("oh man:");
                            }
                            dup2(IN,0);
                            inREDIR = 0;
                            continue;
                        }

                        /* redirect standard out */
                        if(outREDIR == 1){
                            if((OUT = open(op,O_WRONLY | O_CREAT | O_TRUNC,0777)) == NULL){
                                    perror("oh man:");
                            }
                            dup2(OUT,1);
                            outREDIR = 0;
                            continue;
                        }
                        

                        /* redirect standard err */
                        if(errREDIR == 1){
                            if((ERR = open(op,O_WRONLY | O_CREAT | O_TRUNC,0777)) == NULL){
                                    perror("oh man:");
                            }
                            dup2(ERR,2);
                            errREDIR = 0;
                            continue;
                        }
                        
                        /* start a new child, pipe back to this program */
                        if(strcmp(op,"|")==0){
                            if(pipe(fd) != 0) perror("error pipping: ");
                            args[i] = 0;
                            status = forkmebaby(args);
                            break;
                        }
                         
                        /* set flag if a < is encountered */
                        if (strcmp(op,"<")==0) {
                            inREDIR = 1;
                            continue;
                        }

                        /* set flag if a > is encountered */
                        if (strcmp(op,">")==0) {
                            outREDIR = 1;
                            continue;
                            
                        }

                        /* set flag if a 2> is encountered */
                        if (strcmp(op, "2>")==0){
                            
                            errREDIR = 1;
                            continue;
                        }
                        args[i] = malloc(sizeof(op));
                        args[i] = op;
                        i++;
                    }else{

                        args[i] = 0;
                        break;
                    }
                }
                
                if(status == 0)
                execvp(args[0],args);
                perror("bad command:");
                exit(1);
            }
            else{
                wait(&status);
            }
        }
        
    }
}


 /* 
 * forkmebaby method is used if the user wants to pipe information
 * from one process to another.
 * @param id holds the ID of the new process to be forked
 * @param command holds the name of the command to be piped too
 * @param args2[] is an argument list for second command
 */  
 int forkmebaby(char* args[]){
    int id,inREDIR2,outREDIR2,errREDIR2,i;
    int IN2,OUT2,ERR2,status;
    char* command;
    char* args2[8];
    char* op;

    id = fork();
    if(id == 0){
        command = strtok(NULL," \t\n");
        args2[0] = malloc(sizeof(command));
        strcpy(args2[0],command);
        
        close(fd[1]);
        close(0);
        dup2(fd[0],0);
        close(fd[0]);
        status =0;
        i=1;
        while(1){

            if((op = strtok(NULL," \t\n")) != NULL){
                        
                        if(inREDIR2 == 1){
                            if((IN2 = open(op,O_RDONLY)) == NULL){
                                    perror(" Error 2:Input Failed: ");
                            }
                            dup2(IN2,0);
                            inREDIR2 = 0;
                            continue;
                        }

                        if(outREDIR2 == 1){
                            if((OUT2 = open(op,O_WRONLY | O_CREAT | O_TRUNC,0777)) == NULL){
                                    perror("oh man:");
                            }
                            dup2(OUT2,1);
                            outREDIR2 = 0;
                            continue;
                        }
                        
                        if(errREDIR2 == 1){
                            if((ERR2 = open(op,O_WRONLY | O_CREAT | O_TRUNC,0777)) == NULL){
                                    perror("oh man:");
                            }
                            dup2(ERR2,2);
                            errREDIR2 = 0;
                            continue;
                        }
                        
                        if(strcmp(op,"|")==0){
                            if(pipe(fd) != 0) perror("error pipping: ");
                            args2[i] = 0;
                            status = forkmebaby(args2);
                            break;
                        }
                        
                        if (strcmp(op,"<")==0) {
                            inREDIR2 = 1;
                            continue;
                        }
                        if (strcmp(op,">")==0) {
                            outREDIR2 = 1;
                            continue;
                            
                        }
                        if (strcmp(op, "2>")==0){
                            errREDIR2 = 1;
                            continue;
                        }
                        args2[i] = malloc(sizeof(op));
                        args2[i] = op;
                        i++;
                    }
            else{
                args2[i] = 0;
                break;
            }
        }
       
        
        if(status == 0)
        execvp(args2[0],args2);
        perror("bad command piped too\n");

        exit(1);
    }
    else{
        close(fd[0]);
        dup2(fd[1],1);
        if(execvp(args[0], args) == -1) perror("process couldn't be run ");
        close(fd[1]);
        wait(&id);
        return 1;
    }
}                               
